package com.finalministry.server.action;

import java.awt.Color;
import java.io.File;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

import org.apache.commons.io.FileUtils;
import org.finalministry.database.dao.DaoFactory;
import org.finalministry.objects.Congregation;
import org.finalministry.objects.Contact;
import org.finalministry.objects.ContactTypeEnum;
import org.finalministry.objects.Territory;
import org.finalministry.utils.geo.GeoUtils;

public class ExportasKMLfileAction {

	// Marker
	private final static String COLOR = "#COLOR#";
	private final static String COLORINDEX = "#COLORINDEX#";
	private static final String FINALMINISTRY_KML_EXPORT_NAME = "Finalministry KML Export";
	private static final String KML_COORDINATES = "#KML_COORDINATES#";
	private static final String KML_FILE_NAME = "#KML_FILE_NAME#";
	private static final String KML_NAME = "#KML_NAME#";
	private static final String KML_TERRITORIES_NAMES = "#KML_TERRITORIES_NAMES#";
	private static final String KML_POLYGON_NAME = "#KML_POLYGON_NAME#";
	private static final String KMLL_POLYGON_DESCRIPTION = "#KMLL_POLYGON_DESCRIPTION#";
	private static final String KML_STYLE = "#KML_STYLE#";
	private static final String KML_STYLES = "#KML_STYLES#";
	private static final String KML_TEMPLATE_DESCRIPTION = "#KML_TEMPLATE_DESCRIPTION#";
	private static final String KML_TERRITORIES_MARKS = "#KML_TERRITORIES_MARKS#";

	private static final String KML_CONTACTS_TO_BE_VISITED_POINTS = "#KML_CONTACTS_TO_BE_VISITED_POINTS#";
	private static final String KML_CONTACTS_STUDIES_POINTS = "#KML_CONTACTS_STUDIES_POINTS#";
	private static final String KML_CONTACTS_OTHERLANGUAGES_POINTS = "#KML_CONTACTS_OTHERLANGUAGES_POINTS#";
	private static final String KML_CONTACTS_DO_NOT_VISIT_POINTS = "#KML_CONTACTS_DO_NOT_VISIT_POINTS#";

	private static final String KML_STYLE_TOBEVISITED = "#toBeVisited";
	private static final String KML_STYLE_STUDY = "#study";
	private static final String KML_STYLE_OTHERLANGUAGE = "#otherlangue";
	private static final String KML_STYLE_DONOTVISIT = "#doNotVisit";

	// Templates
	private static final String KML_TEMPLATE_COLOR = "\n<Style id=\"color#COLORINDEX#\"><LineStyle><color>7f#COLOR#</color><width>4</width></LineStyle><PolyStyle><color>7f#COLOR#</color></PolyStyle></Style>";
	private final static String KML_TEMPLATE_PATH = "src/main/resources/templates/kml_template.kml";
	private final static String KML_TEMPLATE_NAME = "\n<Placemark><name>#KML_NAME#</name><styleUrl>#point</styleUrl><Point><coordinates>#KML_COORDINATES#</coordinates></Point></Placemark>";
	private final static String KML_TEMPLATE_CONTACT = "\n<Placemark><styleUrl>#KML_STYLE#</styleUrl><Point><coordinates>#KML_COORDINATES#</coordinates></Point></Placemark>";
	private final static String KML_TEMPLATE_POLYGON = "\n<Placemark><name>#KML_POLYGON_NAME#</name><description>#KMLL_POLYGON_DESCRIPTION#</description><styleUrl>#color#COLORINDEX#</styleUrl><Polygon><extrude>1</extrude><altitudeMode>clampToGround</altitudeMode><outerBoundaryIs><LinearRing><coordinates> \n#KML_COORDINATES# </coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark>\n";

	public void exportCongregationsAsMultipleKML(File kmlFolder) {

		try {
			final List<Congregation> congregations = DaoFactory.getInstance().getCongregationDAO().getAll();

			// TODO: export one file per Congregation
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void exportTerritoriesAsKML(File kmlFile) {

		try {
			String kmlTemplate = FileUtils.readFileToString(new File(KML_TEMPLATE_PATH));
			final List<Territory> territories = DaoFactory.getInstance().getTerritoryDAO().getAll();

			final StringBuffer kmlTerritoryNames = new StringBuffer();
			final StringBuffer kmlTerritory = new StringBuffer();
			final StringBuffer kmlStyles = new StringBuffer();

			// 4 main Types of Contact (except disfellowshipped, we do not
			// include them here in this overview)
			final StringBuffer kmlContactsToBeVisited = new StringBuffer();
			final StringBuffer kmlContactsStudy = new StringBuffer();
			final StringBuffer kmlOtherLanguage = new StringBuffer();
			final StringBuffer kmlContactsDoNotVisit = new StringBuffer();

			// Random Color
			final Random random = new Random();
			random.setSeed(Calendar.getInstance().getTimeInMillis());

			for (Territory territory : territories) {

				int count = DaoFactory.getInstance().getContactDAO().countAllByTerritoryID(territory.getId());

				// STYLES
				generateStyleEntry(random, kmlStyles, territory);

				// POLYGON
				generateTerritoryEntry(kmlTerritory, territory, count);

				// NAMES of territories
				generateTerritoryName(kmlTerritoryNames, territory, count);
			}

			final List<Contact> contacts = DaoFactory.getInstance().getContactDAO().getAll();

			for (Contact contact : contacts) {

				DaoFactory.getInstance().getContactDAO().initContactTypeFlags(contact);

				if (contact.getContactType().contains(ContactTypeEnum.TOBEVISITED)) {
					generateContacts(kmlContactsToBeVisited, contact, KML_STYLE_TOBEVISITED);
				}

				if (contact.getContactType().contains(ContactTypeEnum.STUDY)) {
					generateContacts(kmlContactsStudy, contact, KML_STYLE_STUDY);
				}

				if (contact.getContactType().contains(ContactTypeEnum.OTHERLANGUAGE)) {
					generateContacts(kmlOtherLanguage, contact, KML_STYLE_OTHERLANGUAGE);
				}

				if (contact.getContactType().contains(ContactTypeEnum.DONOTVISIT)) {
					generateContacts(kmlContactsDoNotVisit, contact, KML_STYLE_DONOTVISIT);
				}
			}

			String kml = kmlTemplate.replaceAll(KML_CONTACTS_TO_BE_VISITED_POINTS, kmlContactsToBeVisited.toString())
					.replaceAll(KML_CONTACTS_STUDIES_POINTS, kmlContactsStudy.toString())
					.replaceAll(KML_CONTACTS_OTHERLANGUAGES_POINTS, kmlOtherLanguage.toString())
					.replaceAll(KML_CONTACTS_DO_NOT_VISIT_POINTS, kmlContactsDoNotVisit.toString())
					.replaceAll(KML_TERRITORIES_NAMES, kmlTerritoryNames.toString()).replaceAll(KML_TERRITORIES_MARKS, kmlTerritory.toString())
					.replaceAll(KML_FILE_NAME, FINALMINISTRY_KML_EXPORT_NAME).replaceAll(KML_TEMPLATE_DESCRIPTION, "All territories")
					.replaceAll(KML_STYLES, kmlStyles.toString());

			FileUtils.writeStringToFile(kmlFile, kml, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void generateContacts(final StringBuffer kmlContacts, Contact contact, String contactStyle) throws Exception {
		if (contact.getAddress().getCoordinate() == null) {
			System.err.println("Address [ " + contact.getAddress() + " ] has no coordinates.");
			return;
		}

		String kmlCoordinateOfPoint = GeoUtils.getKML_CoordinatesFromPolygon(contact.getAddress().getCoordinate().toText());

		kmlContacts.append(KML_TEMPLATE_CONTACT.replaceAll(KML_COORDINATES, kmlCoordinateOfPoint).replaceAll(KML_STYLE, contactStyle));
	}

	/**
	 * generate the NAMES of territories
	 * 
	 * @param kml
	 * 
	 * @param territory
	 * @param count
	 * @return
	 * @throws Exception
	 */
	private void generateTerritoryName(final StringBuffer kml, Territory territory, int count) throws Exception {

		String kmlCoordinateOfPoint = GeoUtils.getKML_CoordinatesFromPolygon(territory.getArea().getGeometry().getCentroid().toText());
		kml.append(KML_TEMPLATE_NAME.replaceAll(KML_COORDINATES, kmlCoordinateOfPoint)
				.replaceAll(KML_NAME, territory.getNumber() + " - " + territory.getCity())
				.replaceAll(KMLL_POLYGON_DESCRIPTION, "Contacts = " + String.valueOf(count)));
	}

	private void generateTerritoryEntry(final StringBuffer kmlPolygons, Territory territory, int count) throws Exception {
		String kmlCoordinates = GeoUtils.getKML_CoordinatesFromPolygon(territory.getArea().getGeometry().toText());

		kmlPolygons.append(KML_TEMPLATE_POLYGON.replaceAll(KML_COORDINATES, kmlCoordinates)
				.replaceAll(KML_POLYGON_NAME, territory.getNumber() + " - " + territory.getCity())
				.replaceAll(KMLL_POLYGON_DESCRIPTION, "Contacts = " + String.valueOf(count))
				.replaceAll(COLORINDEX, String.valueOf(territory.getNumber())));
	}

	private void generateStyleEntry(Random random, final StringBuffer kmlStyles, Territory territory) {
		// Generate random color
		final float hue = random.nextFloat();
		// Saturation between 0.1 and 0.3
		final float saturation = (random.nextInt(2000) + 1000) / 10000f;
		final float luminance = 0.9f;
		final Color color = Color.getHSBColor(hue, saturation, luminance);
		String hex = String.format("%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());

		kmlStyles.append(KML_TEMPLATE_COLOR.replaceAll(COLORINDEX, String.valueOf(territory.getNumber())).replaceAll(COLOR, hex));
	}

}
